#include "ICuDGGSKernel.cuh"
#include "ISEA4H/ISEA4HImpl.cuh"
#include "ISEA4D/ISEA4DImpl.cuh"
#include "ISEA4T/ISEA4TImpl.cuh"


using namespace NNU::DGGS;
using namespace NNU::DGGS::Base;
using namespace NNU::DGGS::Kernel;
using namespace NNU::DGGS::Kernel::ISEA4H;
using namespace NNU::DGGS::Kernel::ISEA4D;
using namespace NNU::DGGS::Kernel::ISEA4T;

__global__ void initializeKernel(DGGSGridType gridType, ICuDGGSKernel** kernel)
{
    switch (gridType)
    {
        case DGGSGridType::DGGS_ISEA4H:
        {
            CuISEA4HImpl* iesah = new CuISEA4HImpl();
            iesah->init();
            *kernel = iesah;
            break;
        }
        case DGGSGridType::DGGS_ISEA4D:
        {
            CuISEA4DImpl* iesad = new CuISEA4DImpl();
            iesad->init();
            *kernel = iesad;
            break;
        }
        case DGGSGridType::DGGS_ISEA4T:
        {
            CuISEA4TImpl* iesat = new CuISEA4TImpl();
            iesat->init();
            *kernel = iesat;
            break;
        }
        default:
            printf("Entered a wrong type of grid!\n");
    }
}


extern "C" __declspec(dllexport) ICuDGGSKernel* CreateCuKernelObj(DGGSGridType gridType)
{
    ICuDGGSKernel* d_kernel = nullptr;
    ICuDGGSKernel** d_kernel_ptr = nullptr;

    // **分配 GPU 指针的存储空间**
    cudaError_t err = cudaMalloc(&d_kernel_ptr, sizeof(ICuDGGSKernel*));

    // **初始化 GPU 对象**
    initializeKernel<<<1, 1>>>(gridType, d_kernel_ptr);
    cudaDeviceSynchronize();

    // **拷贝 GPU 端的对象指针到 CPU**
    err = cudaMemcpy(&d_kernel, d_kernel_ptr, sizeof(ICuDGGSKernel*), cudaMemcpyDeviceToHost);

    // **释放 `d_kernel_ptr`，避免内存泄漏**
    cudaFree(d_kernel_ptr);

    return d_kernel;
}


__global__ void DestroyKernelOnDevice(ICuDGGSKernel* &kernel)
{
    delete kernel;
}

extern "C" __declspec(dllexport) void DestroyCuKernelObj(ICuDGGSKernel* kernel) {
    // GPU 端删除对象
    DestroyKernelOnDevice<<<1, 1>>>(kernel);
    cudaDeviceSynchronize();
    cudaFree(kernel);
}